package chanrpc

import (
	"Alpaca/conf"
	"Alpaca/log"
	"errors"
	"fmt"
	"runtime"
)

type Server struct {
	functions map[interface{}]interface{} //已注册的函数
	CallChan  chan *CallInfo
}

type CallInfo struct {
	f       interface{}
	args    []interface{}
	retChan chan *RetInfo
	cb      interface{}
}

type RetInfo struct {
	ret interface{}
	err error
	cb  interface{}
}

type Client struct {
	server       *Server
	SyncRetChan  chan *RetInfo
	AsyncRetChan chan *RetInfo
	AsyncCallnum int
}

func assert(i interface{}) []interface{} {
	if i == nil {
		return nil
	} else {
		return i.([]interface{})
	}
}

func NewServer(len int) *Server {
	server := new(Server)
	server.functions = make(map[interface{}]interface{})
	server.CallChan = make(chan *CallInfo, len)
	return server
}

func (s *Server) Close() {
	close(s.CallChan)

	for ci := range s.CallChan {
		s.setret(ci, &RetInfo{
			err: errors.New("chanrpc server is closed"),
		})
	}
}

func (s *Server) Register(id interface{}, f interface{}) {
	switch f.(type) {
	case func([]interface{}):
	case func([]interface{}) interface{}:
	case func([]interface{}) []interface{}:
	default:
		panic(fmt.Sprintf("func %v definition is invalid", id))
	}

	//检测是否已经注册
	if _, ok := s.functions[id]; ok {
		panic(fmt.Sprintf("func %v, this id is already registered", id))
	}

	s.functions[id] = f
}

func (s *Server) setret(ci *CallInfo, ret *RetInfo) (err error) {
	if ci.retChan == nil {
		return
	}

	defer func() {
		if r := recover(); r != nil {
			err = r.(error)
		}
	}()

	ret.cb = ci.cb
	ci.retChan <- ret
	return
}

func (s *Server) Call0(id interface{}, args ...interface{}) error {
	return s.Open(0).Call0(id, args...)
}

func (s *Server) Call1(id interface{}, args ...interface{}) (interface{}, error) {
	return s.Open(0).Call1(id, args...)
}

func (s *Server) CallN(id interface{}, args ...interface{}) ([]interface{}, error) {
	return s.Open(0).CallN(id, args...)
}

func (s *Server) Go(id interface{}, args ...interface{}) {
	f := s.functions[id]
	if f == nil {
		fmt.Println("can not find the func", id)
		return
	}

	defer func() {
		recover()
	}()

	s.CallChan <- &CallInfo{
		f:    f,
		args: args,
	}
}

func (s *Server) exec(ci *CallInfo) (err error) {
	defer func() {
		if r := recover(); r != nil {
			if conf.StackBufLen > 0 {
				buf := make([]byte, conf.StackBufLen)
				len := runtime.Stack(buf, false)
				err = fmt.Errorf("%v: %s", r, buf[:len])
			} else {
				err = fmt.Errorf("%v", r)
			}

			s.setret(ci, &RetInfo{err: fmt.Errorf("%v", r)})
		}
	}()

	if ci == nil {
		log.Debug("ci is nil")
	}

	switch ci.f.(type) {
	case func([]interface{}):
		ci.f.(func([]interface{}))(ci.args)
		return s.setret(ci, &RetInfo{})
	case func([]interface{}) interface{}:
		ret := ci.f.(func([]interface{}) interface{})(ci.args)
		return s.setret(ci, &RetInfo{ret: ret})
	case func([]interface{}) []interface{}:
		ret := ci.f.(func([]interface{}) []interface{})(ci.args)
		return s.setret(ci, &RetInfo{ret: ret})
	}
	panic("here is a bug")
}

func (s *Server) Exec(ci *CallInfo) {
	err := s.exec(ci)
	if err != nil {
		log.Error("%v", err)
	}
}

func (s *Server) Open(len int) *Client {
	c := NewClient(len)
	c.Attach(s)
	return c
}

func NewClient(len int) *Client {
	client := new(Client)
	client.SyncRetChan = make(chan *RetInfo, 1)
	client.AsyncRetChan = make(chan *RetInfo, len)
	return client
}

func (c *Client) Attach(s *Server) {
	c.server = s
}

func (c *Client) getfunc(id interface{}, n int) (f interface{}, err error) {
	if c.server == nil {
		err = errors.New("server is not attached")
		return
	}

	//获取对应函数
	f = c.server.functions[id]
	if f == nil {
		err = fmt.Errorf("this function %v is not registered", id)
		return
	}

	var ok bool
	switch n {
	case 0:
		_, ok = f.(func([]interface{}))
	case 1:
		_, ok = f.(func([]interface{}) interface{})
	case 2:
		_, ok = f.(func([]interface{}) []interface{})
	default:
		panic("here is a bug")
	}

	if !ok {
		err = fmt.Errorf("function %v return type is not match", id)
	}
	return
}

func (c *Client) call(ci *CallInfo, block bool) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = r.(error)
		}
	}()

	if block { //同步调用
		c.server.CallChan <- ci
	} else { //异步调用
		select {
		case c.server.CallChan <- ci:
		default:
			err = errors.New("chanrpc CallChan is full")
		}
	}
	return
}

func (c *Client) Call0(id interface{}, args ...interface{}) error {
	f, err := c.getfunc(id, 0)
	if err != nil {
		return err
	}

	err = c.call(&CallInfo{
		f:       f,
		args:    args,
		retChan: c.SyncRetChan,
	}, true)
	if err != nil {
		return err
	}

	ret := <-c.SyncRetChan
	return ret.err
}

func (c *Client) Call1(id interface{}, args ...interface{}) (interface{}, error) {
	f, err := c.getfunc(id, 1)
	if err != nil {
		return nil, err
	}

	err = c.call(&CallInfo{
		f:       f,
		args:    args,
		retChan: c.SyncRetChan,
	}, true)
	if err != nil {
		return nil, err
	}

	ret := <-c.SyncRetChan
	return ret.ret, ret.err
}

func (c *Client) CallN(id interface{}, args ...interface{}) ([]interface{}, error) {
	f, err := c.getfunc(id, 2)
	if err != nil {
		return nil, err
	}

	err = c.call(&CallInfo{
		f:       f,
		args:    args,
		retChan: c.SyncRetChan,
	}, true)
	if err != nil {
		return nil, err
	}

	ret := <-c.SyncRetChan
	return assert(ret.ret), ret.err
}

func (c *Client) asynCall(id interface{}, args []interface{}, cb interface{}, n int) {
	f, err := c.getfunc(id, n)
	if err != nil {
		c.AsyncRetChan <- &RetInfo{err: err, cb: cb}
		return
	}

	err = c.call(&CallInfo{
		f:       f,
		args:    args,
		retChan: c.AsyncRetChan,
		cb:      cb,
	}, false)
	if err != nil {
		c.AsyncRetChan <- &RetInfo{err: err, cb: cb}
		return
	}
}

func (c *Client) AsynCall(id interface{}, _args ...interface{}) {
	if len(_args) < 1 {
		panic("callback function not found")
	}

	args := _args[:len(_args)-1]
	cb := _args[len(_args)-1]

	var n int
	switch cb.(type) { //根据cb的参数推测f的类型
	case func(error):
		n = 0
	case func(interface{}, error):
		n = 1
	case func([]interface{}, error):
		n = 2
	default:
		panic("callback definition is invalid")
	}

	if c.AsyncCallnum == cap(c.AsyncRetChan) {
		execCb(&RetInfo{err: errors.New("too many calls"), cb: cb})
		return
	}

	c.asynCall(id, args, cb, n)
	c.AsyncCallnum++
}

func execCb(ret *RetInfo) {
	defer func() {
		if r := recover(); r != nil {
			if conf.StackBufLen > 0 {
				buf := make([]byte, conf.StackBufLen)
				l := runtime.Stack(buf, false)
				log.Error("%v: %s", r, buf[:l])
			} else {
				log.Error("%v", r)
			}
		}
	}()

	//根据类型进行回调
	switch ret.cb.(type) {
	case func(error):
		ret.cb.(func(error))(ret.err)
	case func(interface{}, error):
		ret.cb.(func(interface{}, error))(ret.ret, ret.err)
	case func([]interface{}, error):
		ret.cb.(func([]interface{}, error))(assert(ret.ret), ret.err)
	default:
		panic("bug")
	}
	return
}

func (c *Client) Cb(ret *RetInfo) {
	c.AsyncCallnum--
	execCb(ret)
}

func (c *Client) Close() {
	if c.AsyncCallnum > 0 {
		c.Cb(<-c.AsyncRetChan)
	}
}

func (c *Client) Idle() bool {
	return c.AsyncCallnum == 0
}
